﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using VegetableStore.Domains;
using VegetableStore.Providers;
using NHibernate;
using System.Globalization;
using VegetableStore.Util;
using System.Collections;
using NHibernate.Transform;
using VegetableStore.Dto;

namespace VegetableStore.Controllers
{
    [AllowAnonymous]
    public class UserController : Controller
    {
        private ISession nhibernateSession;

        public UserController()
        {
            nhibernateSession = SessionProvider.Instance.GetSession();
        }

        public ActionResult UserTest()
        {
            return View();
        }

        private string GenerateToken(string phoneNumber)
        {
            return CipherUtil.Encrypt(phoneNumber + DateTime.Now.Millisecond);
        }
                
        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult SignUp(string phoneNumber, string pwd, string name, string birthday, string occupation, string gender, string email, int? favoriteMarketId)
        {
            try
            {
                if (phoneNumber == null) return Json(new { result = "FAILURE", msg = "phoneNumber가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (pwd == null) return Json(new { result = "FAILURE", msg = "pwd가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (favoriteMarketId == null) return Json(new { result = "FAILURE", msg = "favoriteMarketId가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                
                Market favoriteMarket = nhibernateSession.Get<Market>(favoriteMarketId);
                if (favoriteMarket == null) return Json(new { result = "FAILURE", msg = "favoriteMarketId에 해당되는 시장이 없습니다." }, JsonRequestBehavior.AllowGet);

                Users user = nhibernateSession.Get<Users>(phoneNumber);
                if (user != null) return Json(new { result = "FAILURE", msg = "이미 등록된 사용자입니다." }, JsonRequestBehavior.AllowGet);
                
                if (birthday != null)
                {
                    try
                    {
                        DateTime birthdayDateTime = DateTime.ParseExact(birthday, "yyyyMMdd", CultureInfo.InvariantCulture); //타입체크필요
                    }
                    catch
                    {
                        return Json(new { result = "FAILURE", msg = "birthday타입이 yyyyMMdd가 아닙니다." }, JsonRequestBehavior.AllowGet);
                    }
                }
                if (gender != null && gender != "M" && gender != "W")
                {
                    return Json(new { result = "FAILURE", msg = "gender타입이 M/W가 아닙니다." }, JsonRequestBehavior.AllowGet);
                }
                                
                string token =GenerateToken(phoneNumber);
                user = new Users()
                {
                    PhoneNumber = phoneNumber,
                    Pwd = CipherUtil.Encrypt(pwd),
                    Name = name,
                    Birthday = birthday,
                    Occupation = occupation,
                    Gender = gender,
                    Email = email,
                    FavoriteMarket = nhibernateSession.Load<Market>(favoriteMarketId),
                    Token = token
                };
                using (var tx = nhibernateSession.BeginTransaction())
                {
                    try
                    {
                        nhibernateSession.Save(user);
                        nhibernateSession.Flush();
                        tx.Commit();
                    }
                    catch (Exception te)
                    {
                        tx.Rollback();
                        SessionProvider.Instance.CloseSession();
                        throw te;
                    }
                }
                return Json(new { result = "SUCCESS", data = new { token = token } }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }
                
        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult GetUser(string token)
        {
            try
            {
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);                
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);
                Users user = nhibernateSession.CreateQuery("from Users where token = :token")
                    .SetString("token", token)
                    .UniqueResult<Users>();
                return Json(new { result = "SUCCESS", data = user }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult Login(string phoneNumber, string pwd)
        {
            try
            {
                string type = "CUSTOMER";
                if (phoneNumber == null) return Json(new { result = "FAILURE", msg = "phoneNumber가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (pwd == null) return Json(new { result = "FAILURE", msg = "pwd가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);

                string encrypedPwd = CipherUtil.Encrypt(pwd);
                string token = GenerateToken(phoneNumber);

                Users user = nhibernateSession.Get<Users>(phoneNumber);
                if (user == null) return Json(new { result = "FAILURE", msg = "등록되지 않은 사용자입니다." }, JsonRequestBehavior.AllowGet);
                if (user.Pwd != encrypedPwd) return Json(new { result = "FAILURE", msg = "비밀번호가 올바르지 않습니다." }, JsonRequestBehavior.AllowGet);

                user.Token = token;
                using (var tx = nhibernateSession.BeginTransaction())
                {
                    try
                    {
                        nhibernateSession.Update(user);
                        if (user.PhoneNumber == "01084266985") throw new Exception();
                        nhibernateSession.Flush();
                        tx.Commit();
                    }
                    catch (Exception te)
                    {
                        tx.Rollback();
                        SessionProvider.Instance.CloseSession();
                        throw te;
                    }
                }               
                IList<Usersstore> usersStoreList = nhibernateSession.QueryOver<Usersstore>()
                    .JoinQueryOver<Users>(x => x.Users)
                    .Where(y => y.PhoneNumber == user.PhoneNumber)
                    .List();
                if (usersStoreList.Count > 0) type = "TRADER";
                return Json(new { result = "SUCCESS", data = new { token = token, type = type } }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult Logout(string token)
        {
            try
            {
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);                                
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);
                Users user = nhibernateSession.CreateQuery("from Users where token = :token")
                    .SetString("token", token)
                    .UniqueResult<Users>();
                user.Token = null;
                using (var tx = nhibernateSession.BeginTransaction())
                {
                    try
                    {
                        nhibernateSession.Merge<Users>(user);
                        nhibernateSession.Flush();
                        tx.Commit();
                    }
                    catch (Exception te)
                    {
                        tx.Rollback();
                        SessionProvider.Instance.CloseSession();
                        throw te;
                    }
                }
                return Json(new { result = "SUCCESS" }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult GetFavoriteMarket(string token)
        {
            try
            {
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);                                
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);
                Users user = nhibernateSession.CreateQuery("from Users where token = :token")
                    .SetString("token", token)
                    .UniqueResult<Users>();
                return Json(new { result = "SUCCESS", data = new { FavoriteMarket = user.FavoriteMarket } }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult GetMyStores(string token)
        {
            try
            {
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);
                
                string query = "select S.id, Image_id, S.Market_id, S.name, [address], phone from Store S ";
                query += "join UsersStore US on S.Id = US.Store_id ";
                query += "join Users U on U.phone_number = US.Users_id ";
                query += "where U.token = :token";

                IList<StoreDto> myStores = nhibernateSession.CreateSQLQuery(query)
                    .SetString("token", token)
                    .SetResultTransformer(new AliasToBeanResultTransformer(typeof(StoreDto)))
                    .List<StoreDto>();

                return Json(new { result = "SUCCESS", data = new { MyStores = myStores } }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }
    }
}
